CVE-2018-5767 TENDA栈溢出漏洞
打算学习一下IOT相关的漏洞挖掘知识。
之前简单模拟过D-Link DIR-816 A2的任意命令执行漏洞,但是感觉能学到的东西较少,这次来复现一下一个TENDA的栈溢出漏洞。
只不过可惜的是没法完整复现rop链的调用过程。
实验目的
复现 CVE-2018-5767,是TENDA-AC15 路由器V15.03.1.16版本固件上的一个栈溢出漏洞,架构是arm架构,初步学习下IOT的漏洞挖掘。
环境配置
Ubuntu虚拟机,因为Ubuntu安装qemu很方便。
qemu环境
apt-get install qemu
pwndbg等环境的安装,可以参考我之前的文章,需要注意的点就是可能会和Ubuntu自带的gdb冲突,解决方法就是在自己的主目录下创建.gdbinit文件,写入pwndbg目录下gdbinit.py的路径
source gdbinit.py路径
固件US_AC15V1.0BR_V15.03.1.16_multi_TD01.bin下载地址:
https://drivers.softpedia.com/get/Router-Switch-Access-Point/Tenda/Tenda-AC15-Router-Firmware-1503116.shtml
仿真模拟
binwalk导出固件文件系统,没有加固这些。
binwalk -Me US_AC15V1.0BR_V15.03.1.16_multi_TD01.bin
查看一些信息,32位,arm架构。
readelf -h bin/busybox
然后找到路由器管理界面对应的httpd服务程序。
grep -r httpd .
尝试使用qemu启动。
#安装qemu和arm的动态链接库
sudo apt install qemu libc6-arm* libc6-dev-arm*
cp $(which qemu-arm-static) .
sudo chroot ./ ./qemu-arm-static ./bin/httpd
然后发现启动会失败,调试分析后,发现程序会开在这里,我们需要控制流程,做一些patch,免得每次都要修改。
然后启动,成功启动,但是ip不对,我们需要建立一个虚拟网桥br0,这里也能在代码中得到体现。
sudo apt install uml-utilities bridge-utils
sudo brctl addbr br0
sudo brctl addif br0 eth0
sudo ifconfig br0 up
sudo dhclient br0
成功后,执行ifconfig命令会发现,多了一个bro网。
然后重新尝试启动,正常启动。
当然模拟只是模拟,模拟出的环境是没法进行web端的页面访问的,但是后面版本的固件可以。
杀死相关进程。
//查找和httpd相关的进程
ps -ef|grep /bin/httpd
//根据pid杀掉进程
kill -9 pid
//查看端口占用
netstat -tunlp |grep 端口号
漏洞分析
根据参考文章来说漏洞是COOKIE包头中特制的‘password’参数可以照成栈溢出,这里由于没有真机,无法实际操作,只能默认有这么一个漏洞点。其对应的函数在R7WebsSecurityHandler。
接下来调试分析。
quem以调试方式挂起启动httpd。
sudo chroot ./ ./qemu-arm-static -g 1234 ./bin/httpd
pwndbg远程连接1234端口进行调试,当然也可以使用ida进行远程调试。
gdb-multiarch ./bin/httpd
target remote :1234
continue //先在分析的函数打断点后再进行continue
target remote :1234会自动先停到start处。
先给一个分析后的,方便懂原理。
然后我们可以先在password那里打个断点,然后continue,然后执行脚本,就会断下来。
b *0x02DCE8
test脚本。
1 |
|
然后就会断下来,接下来调试。
sscanf。
执行完后,可以看到已经造成了栈溢出,覆盖了后面的数据。
然后也可以用x /100xb 0xfffeeacc,去查看下内存。
然后直接continue,看看会执行到哪去。
程序会报错误,用bt查看调用链,程序会被中间的流程执行截断,然后由于栈溢出,导致报错,所以我们需要提前能结束R7WebsSecurityHandler函数,然后我们通过栈溢出控制其返回执行流。
而正好后面有一个判断可以,提前return。
接下来我们需要得到偏移量,根据ida里面的数据可以得到大概是448字节就会覆盖,但是由于是arm架构,指令不同,而且我们也需要实际的测试。
构造如下playload,来确定偏移。
1 |
|
确定偏移为448。
漏洞利用
其他文章中的rop链,payload = “A”*444 +”.png” + p32(gadget1) + p32(system_addr) + p32(gadget2) + cmd
0x2ED18 : POP {R4-R6,R11,PC} //pop pc会到我们的链的起始点gadget1
rop链。
gadget1 :pop {r3, pc} //将system的地址给到r3,将gadget2给到pc
gadget2 :mov r0, sp ; //将cmd的起始栈地址给到r0,作为system的参数
blx r3 //执行system函数
这里我复现遇到了点问题,就是vmmap指令得不到libc的基址,这导致没法构造有效的rop链,并且在原程序中也找不到一些有效的语句来构造,所以这里我打算自己调试,然后修改某些值来达到一个执行puts(“某字符串”)
获取system的地址,readelf -s ./bin/httpd | grep system
同样可以获取puts函数地址。
当然如果需要其他的语句,也可以使用ROPgadget,正则匹配想要的语句。
exp
1 |
|
然后修改r0的值为程序中某一字符串的地址。
然后continue,发现成功打印。
参考
https://www.anquanke.com/post/id/204326#h2-2